variables: &variables
  SFOS_VERSION: 4.4.0.58
  GIT_FETCH_EXTRA_FLAGS: --tags
  RUST_BACKTRACE: full

include:
  # Awesome OpenRepos script by @nobodyinperson/Yann Büchau
  - https://gitlab.com/nobodyinperson/python3-openrepos-webclient/-/raw/master/openrepos-upload-rpm.gitlab-ci.yml
  # The MergeRequest-Pipelines template makes your pipelines run for the default branch, tags, and all types of merge request pipelines.
  - template: 'Workflows/MergeRequest-Pipelines.gitlab-ci.yml'
  - project: "dependabot-gitlab/dependabot-standalone"
    file: ".gitlab-ci.yml"

.dependabot-gitlab:
  stage: deploy

stages:
  - build
  - test
  - format
  - deploy

.rust: &rust
  cache: &rust-cache
    paths:
      - target/
      - cargo/bin/
      - cargo/registry/index/
      - cargo/registry/cache/
      - cargo/git/db/
  before_script:
    - apt-get update
    - apt-get install -y --no-install-recommends libsqlcipher-dev qtbase5-dev qtbase5-private-dev qt5-qmake cmake qtdeclarative5-dev qtbase5-dev-tools qttools5-dev-tools protobuf-compiler libdbus-1-dev libqt5opengl5-dev libssl-dev
    - cargo --version
    - rustc --version

.rust-stable: &rust-stable
  <<: *rust
  image: rust
  cache:
    <<: *rust-cache
    key:
      prefix: rust-stable
      files:
        - Cargo.lock

.rust-nightly: &rust-nightly
  <<: *rust
  variables:
    QT_SELECT: 5
    <<: *variables
  image: rustlang/rust:nightly
  allow_failure: true
  cache:
    <<: *rust-cache
    key:
      prefix: rust-nightly
      files:
        - Cargo.lock

.build-sailfishos: &build-sailfishos
  image: registry.gitlab.com/whisperfish/sailo-rs/rust-$MER_ARCH-$SFOS_VERSION:latest
  stage: build
  variables:
    CARGO_HOME: /home/mersdk/cargo
  artifacts:
    paths:
      - RPMS/*.rpm
        # i686 is the "native" target, so we catch them in the `target` dir directly.
      - target/release/whisperfish-migration-dry-run
      - target/release/fetch-signal-attachment
      - target/release/harbour-whisperfish
      - target/*/release/whisperfish-migration-dry-run
      - target/*/release/fetch-signal-attachment
      - target/*/release/harbour-whisperfish
  cache:
    paths:
      - cargo/bin/
      - cargo/registry/index/
      - cargo/registry/cache/
      - cargo/git/db/
    key: target-$MER_ARCH
  script:
    - .ci/build-with-mb2.sh

build:sailfishos:latest:armv7hl:
  extends: .build-sailfishos
  variables:
    <<: *variables
    MER_ARCH: armv7hl
    TARGET_VERSION: $SFOS_VERSION
    DIST: .sf4
  rules:
    - if: $CI_PIPELINE_SOURCE == "schedule"
      when: never
    - when: on_success

build:sailfishos:3.4:armv7hl:
  extends: .build-sailfishos
  variables:
    <<: *variables
    MER_ARCH: armv7hl
    TARGET_VERSION: 3.4.0.24
    SFOS_VERSION: 4.1.0.24
    DIST: .sf3
  rules:
    - if: $CI_PIPELINE_SOURCE == "schedule"
      when: never
    - when: on_success

build:sailfishos:latest:i486:
  extends: .build-sailfishos
  variables:
    <<: *variables
    MER_ARCH: i486
    TARGET_VERSION: $SFOS_VERSION
    DIST: .sf4
  cache:
    <<: *rust-cache
    key: "target-i486-$CI_COMMIT_REF_SLUG"
  rules:
    - if: $CI_PIPELINE_SOURCE == "schedule"
      when: never
    - when: on_success

## We don't build 3.4 for i486, because
#  in that case, rust 1.52 gets installed without the sb2 passthrough,
#  and the 3.4 runtime doesn't provide all necessary dependencies.
#  If this bothers someone (I don't think there's any i486 device that doesn't support 4.3;
#  check conversation at https://matrix.to/#/!clfpfblSRQUbEUGwsD:rubdos.be/$QANC2ZqJuGElnp2Bkvll_4KLmmSmZUqPgthzzT1KRT0?via=libera.chat&via=matrix.org&via=rubdos.be)
# build:sailfishos:3.4:i486:
#  extends: .build-sailfishos
#   variables:
#     <<: *variables
#     MER_ARCH: i486
#     TARGET_VERSION: 3.4.0.24
#     DIST: .sf3
#   rules:
#    - if: $CI_PIPELINE_SOURCE == "schedule"
#      when: never
#    - when: on_success

build:sailfishos:latest:aarch64:
  extends: .build-sailfishos
  variables:
    <<: *variables
    MER_ARCH: aarch64
    TARGET_VERSION: $SFOS_VERSION
    DIST: .sf4
  rules:
    - if: $CI_PIPELINE_SOURCE == "schedule"
      when: never
    - when: on_success

build:sailfishos:3.4:aarch64:
  extends: .build-sailfishos
  variables:
    <<: *variables
    MER_ARCH: aarch64
    TARGET_VERSION: 3.4.0.24
    SFOS_VERSION: 4.1.0.24
    DIST: .sf3
  rules:
    - if: $CI_PIPELINE_SOURCE == "schedule"
      when: never
    - when: on_success

build:host:stable:
  <<: *rust-stable
  stage: build
  script:
    - cargo build --features bundled-sqlcipher
  rules:
    - if: $CI_PIPELINE_SOURCE == "schedule"
      when: never
    - when: on_success

build:host:nightly:
  <<: *rust-nightly
  stage: build
  needs:
    # Run only if stable already succeeded. We don't use the results of this
    # job and run it only to test future versions of rust. See the discussion
    # in https://gitlab.com/whisperfish/whisperfish/-/merge_requests/202
    - build:host:stable
  script:
    - cargo build --features bundled-sqlcipher
  rules:
    - if: $CI_PIPELINE_SOURCE == "schedule"
      when: never
    - when: on_success

build:host:stable:docs:
  <<: *rust-stable
  stage: build
  needs:
    - build:host:stable
  script:
    - cargo doc --no-deps --document-private-items -p harbour-whisperfish -p libsignal-service -p libsignal-protocol -p zkgroup  -p whisperfish
  artifacts:
    paths:
      - target/doc
  # This job has no large overhead. Thus, we fetch only the cache from the
  # build job and don't interfere with later tests jobs.
  cache:
    <<: *rust-cache
    key:
      prefix: rust-stable
      files:
        - Cargo.lock
    policy: pull
  rules:
    - if: $CI_PIPELINE_SOURCE == "schedule"
      when: never
    - when: on_success

build:host:stable:tarball:
  <<: *rust-stable
  stage: build
  needs:
    - build:host:stable
  before_script:
    - export P="${CI_PROJECT_NAME}-${CI_COMMIT_TAG#v}"
  script:
    - git archive --prefix="${P}/" -o ${P}.tar ${CI_COMMIT_TAG}
    - cargo vendor ${P}/vendor
    - tar --append -f ${P}.tar ${P}
    - gzip ${P}.tar
  after_script:
    - echo TGZ_JOB_ID=${CI_JOB_ID} >> build.env
    - echo PACKAGE_NAME="${CI_PROJECT_NAME}-${CI_COMMIT_TAG#v}" >> build.env
  artifacts:
    paths:
      - ./*.tar.gz
    reports:
      dotenv: build.env
  cache:
    <<: *rust-cache
    key:
      prefix: rust-stable
      files:
        - Cargo.lock
    policy: pull
  only:
    - tags

qmllint:
  <<: *rust
  stage: format
  image: rust
  cache: {}
  script:
    - "qmllint qml/**/*.qml"
  rules:
    - if: $CI_PIPELINE_SOURCE == "schedule"
      when: never
    - when: on_success

test:stable:
  <<: *rust-stable
  stage: test
  needs:
    - build:host:stable
  script:
    - cargo test --features whisperfish/bundled-sqlcipher
  rules:
    - if: $CI_PIPELINE_SOURCE == "schedule"
      when: never
    - when: on_success

test:cargo-deny:
  <<: *rust-stable
  stage: test
  needs:
    - build:host:stable
  script:
    - cargo install --locked cargo-deny
    - export PATH="$CARGO_HOME/bin:$PATH"
    - cargo deny check
  cache: {}
  rules:
    - if: $CI_PIPELINE_SOURCE == "schedule" && $CI_SCHEDULE == "cargo-deny"
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
      allow_failure: true

test:stable:diesel-schema:
  <<: *rust-stable
  stage: test
  needs:
    - build:host:stable
  script:
    - rustup component add rustfmt
    # Diesel is not running a long time/often. We don't need the release
    # version here and the debug version is enough. We save a lot of
    # compilation time for small overhead when running the binary.
    - cargo install -f --debug diesel_cli --version ^2 --features "sqlite-bundled"
    - export PATH="$CARGO_HOME/bin:$PATH"
    - export DATABASE_URL=test_whisperfish.db
    - diesel setup
    - diesel migration run
    - diesel print-schema > whisperfish-store/src/schema.rs
    - cargo fmt -- --check whisperfish-store/src/schema.rs
  # Diesel does not need to access build artifacts of other stages.
  cache: {}
  rules:
    - if: $CI_PIPELINE_SOURCE == "schedule"
      when: never
    - when: on_success

fmt:stable:
  <<: *rust-stable
  stage: format
  needs:
    - build:host:stable
  # Cargo fmt does not need external packages.
  before_script: []
  script:
    - rustup component add rustfmt
    - cargo fmt -- --check
  # Cargo fmt does not need to access the cache. With it's own cache, it does
  # not interfere with `coverage:stable` and `clippy:stable`. There is nothing
  # to store in the cache either.
  cache: {}
  rules:
    - if: $CI_PIPELINE_SOURCE == "schedule"
      when: never
    - when: on_success

coverage:stable:
  <<: *rust-stable
  image: xd009642/tarpaulin
  stage: format
  needs:
    - test:stable
  variables:
    <<: *variables
    # Not needed anymore after the Tarpaulin image is on Debian Bullseye
    QT_SELECT: qt5
  script:
    # Add --all-features and --all-targets some time in the future. Tarpaulin
    # runs only at linux-x86 and would need the whisperfish sdk to build all
    # features.
    - cargo tarpaulin --features bundled-sqlcipher --exclude-files cargo/* --out xml
  artifacts:
    name: ${CI_JOB_NAME}-${CI_COMMIT_REF_NAME}-${CI_COMMIT_SHA}
    reports:
      coverage_report:
        coverage_format: cobertura
        path: cobertura.xml
  coverage: '/^\d+.\d+% coverage/'
  # Tarpaulin needs its own cache as many more information are stored from
  # other crates. In addition, `clippy:stable` can pull/push the cache from
  # `test:stable` and the tarpaulin job does not interfere with the clippy
  # cache.
  cache:
    <<: *rust-cache
    key:
      prefix: rust-stable-tarpaulin
      files:
        - Cargo.lock
  rules:
    - if: $CI_PIPELINE_SOURCE == "schedule"
      when: never
    - when: on_success

clippy:stable:
  <<: *rust-stable
  stage: format
  needs:
    - test:stable
  script:
    - rustup component add clippy
    # the following command should be used but needs sailfish SDK
    # - cargo clippy --all-targets --all-features -- -D warnings
    #
    # Two allows are put in globally, because they occur from macro invocations.
    # derive_partial_eq_without_eq occurs by prost, and prost suggests to disable the lint globally:
    #   https://github.com/tokio-rs/prost/issues/661
    # useless-transmute
    - cargo clippy --all-targets -- -A clippy::derive_partial_eq_without_eq -A clippy::useless_transmute
  rules:
    - if: $CI_PIPELINE_SOURCE == "schedule"
      when: never
    - when: on_success

clippy:stable-warnings:
  <<: *rust-stable
  stage: format
  allow_failure: true
  needs:
    - test:stable
  script:
    - rustup component add clippy
    # the following command should be used but needs sailfish SDK
    # - cargo clippy --all-targets --all-features -- -D warnings
    #
    # For allows, see above
    - cargo clippy --all-targets -- -D warnings -A clippy::derive_partial_eq_without_eq -A clippy::useless_transmute
  rules:
    - if: $CI_PIPELINE_SOURCE == "schedule"
      when: never
    - when: on_success

.translations: &translations
  image: debian
  needs: []
  before_script:
    - apt-get update
    - apt-get install --no-install-recommends -y git curl qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools qttools5-dev-tools ca-certificates

translations:check:
  <<: *translations
  stage: test
  rules:
    - if: $CI_PIPELINE_SOURCE == "schedule"
      when: never
    - if: '$CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH'
  script:
    - .ci/check-translations.sh

translations:update:
  <<: *translations
  stage: deploy
  rules:
    - if: $CI_PIPELINE_SOURCE == "schedule"
      when: never
    - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
  variables:
    # Clone with full depth for translation contribution analysis
    GIT_STRATEGY: clone
    GIT_DEPTH: 0
  script:
    - .ci/update-translation-contributors.sh
    - .ci/update-translations.sh

test:sailfishos:validate-rpms:
  stage: test
  image: registry.gitlab.com/whisperfish/sailo-rs/rpm-validator:latest
  allow_failure: true
  dependencies:
    - build:sailfishos:latest:armv7hl
    - build:sailfishos:latest:aarch64
    - build:sailfishos:latest:i486
  needs:
    - build:sailfishos:latest:armv7hl
    - build:sailfishos:latest:aarch64
    - build:sailfishos:latest:i486
  script:
    - for rpm in RPMS/*.rpm; do rpmvalidation.sh $rpm; done
  rules:
    - if: $CI_PIPELINE_SOURCE == "schedule"
      when: never
    - when: on_success

notify_matrix_build_ready:
  stage: deploy
  image: debian
  rules:
    - if: $CI_PIPELINE_SOURCE == "schedule"
      when: never
    - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
  environment:
    name: Whisperfish Matrix channel
    url: $MATRIX_HOME_SERVER
  needs:
    - build:sailfishos:latest:armv7hl
    - build:sailfishos:latest:aarch64
    - build:sailfishos:latest:i486
  before_script:
    - apt-get update
    - apt-get install --no-install-recommends -y git curl jq ca-certificates
  script:
    - .ci/send-matrix-build-notification.sh

pages:
  dependencies:
    - build:host:stable:docs
  needs:
    - build:host:stable:docs
  stage: deploy
  rules:
    - if: $CI_PIPELINE_SOURCE == "schedule"
      when: never
    - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
  script:
    - mkdir -p public
    - mv target/doc public/
  artifacts:
    paths:
      - public

.deploy:openrepos: &deploy-openrepos
  stage: deploy
  extends: .openrepos-upload-rpm
  variables: &openrepos-vars
    OPENREPOS_UPLOAD_RPM_PLATFORM: SailfishOS
    OPENREPOS_UPLOAD_RPM_CATEGORY: Applications
  needs: &openrepos-needs
    - build:sailfishos:latest:armv7hl
    - build:sailfishos:latest:i486
    - build:sailfishos:latest:aarch64
    - build:sailfishos:3.4:armv7hl
    # - build:sailfishos:3.4:i486
    - build:sailfishos:3.4:aarch64
    - test:stable
  dependencies:
    - build:sailfishos:latest:armv7hl
    - build:sailfishos:latest:i486
    - build:sailfishos:latest:aarch64
    - build:sailfishos:3.4:armv7hl
    # - build:sailfishos:3.4:i486
    - build:sailfishos:3.4:aarch64
  only:
    - tags

deploy:openrepos:wf-sf3:
  <<: *deploy-openrepos
  variables:
    <<: *openrepos-vars
    OPENREPOS_UPLOAD_RPM_APPNAME: "Whisperfish (SailfishOS 3.4)"
  environment:
      name: OpenRepos SF3
      url: https://openrepos.net/content/rubdos/whisperfish-sailfishos-34
  before_script:
    - mv RPMS/*.sf3.*.rpm .
    - rm *shareplugin*rpm
    - ls *.rpm

deploy:openrepos:wf-sf4:
  <<: *deploy-openrepos
  variables:
    <<: *openrepos-vars
    OPENREPOS_UPLOAD_RPM_APPNAME:  Whisperfish
  environment:
      name: OpenRepos
      url: https://openrepos.net/content/rubdos/whisperfish
  before_script:
    - mv RPMS/*.sf4.*.rpm .
    - rm *shareplugin*rpm
    - ls *.rpm

deploy:openrepos:wf-shareplugin-sf3:
  <<: *deploy-openrepos
  variables:
    <<: *openrepos-vars
    OPENREPOS_UPLOAD_RPM_APPNAME: "Whisperfish shareplugin (SailfishOS 4.2 or below)"
  environment:
      name: "OpenRepos shareplugin 4.3"
      url: https://openrepos.net/content/rubdos/whisperfish-shareplugin-sailfishos-42-or-below
  before_script:
    - mv RPMS/*shareplugin*.sf3.*.rpm .
    - ls *.rpm

deploy:openrepos:wf-shareplugin-sf4:
  <<: *deploy-openrepos
  variables:
    <<: *openrepos-vars
    OPENREPOS_UPLOAD_RPM_APPNAME: "Whisperfish shareplugin (SailfishOS 4.3+)"
  environment:
      name: "OpenRepos shareplugin 4.3"
      url: https://openrepos.net/content/rubdos/whisperfish-shareplugin-sailfishos-43
  before_script:
    - mv RPMS/*shareplugin*.sf4.*.rpm .
    - ls *.rpm

deploy:gitlab:tarball:
  stage: deploy
  image: registry.gitlab.com/gitlab-org/release-cli:latest
  needs:
    - job: build:host:stable:tarball
      artifacts: true
  script:
    - echo "Running release job"
  release:
    name: Release ${CI_COMMIT_TAG}
    description: Created using the release-cli
    tag_name: ${CI_COMMIT_TAG}
    ref: ${CI_COMMIT_TAG}
    assets:
      links:
        - name: ${PACKAGE_NAME}.tar.gz
          url: ${CI_PROJECT_URL}/-/jobs/${TGZ_JOB_ID}/artifacts/raw/${PACKAGE_NAME}.tar.gz
  only:
    - tags

dry-run:triage:
  stage: test
  image: ruby:2.4
  script:
    - gem install gitlab-triage
    - gitlab-triage --help
    - gitlab-triage --dry-run --token $PRIVATE_TOKEN --source projects --source-id $CI_PROJECT_PATH
  when: manual

policy:run:
  stage: deploy
  image: ruby:2.4
  script:
    - gem install gitlab-triage
    - gitlab-triage --token $PRIVATE_TOKEN --source projects --source-id $CI_PROJECT_PATH
  when: manual

.schedule:policyrun:
  stage: deploy
  image: ruby:2.4
  script:
    - gem install gitlab-triage
    - gitlab-triage --token $PRIVATE_TOKEN --source projects --source-id $CI_PROJECT_PATH
  rules:
    - if: $CI_PIPELINE_SOURCE == "schedule" && $CI_SCHEDULE == "policy"
